package android.tusnotas.services;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.IBinder;
import android.tusnotas.activities.R;
import android.tusnotas.beans.AppVersion;
import android.tusnotas.beans.Instance;
import android.tusnotas.beans.ListaNotificaciones;
import android.tusnotas.beans.PushStatus;
import android.tusnotas.core.GradeAnalyser;
import android.tusnotas.core.GradeAnalyserStatuses;
import android.tusnotas.core.PushAckAnalyser;
import android.tusnotas.core.PushAnalyser;
import android.tusnotas.core.PushSubscriptionAnalyser;
import android.tusnotas.core.PushUnsubscriptionAnalyser;
import android.tusnotas.core.VersionAnalyser;
import android.tusnotas.exception.ProcessingInstancesException;
import android.tusnotas.exception.RemoteReadingException;
import android.tusnotas.model.TusNotasModel;
import android.tusnotas.notification.TusNotasNotification;
import android.tusnotas.util.*;
import android.util.Log;

public class WebChecker extends Service{

	private final Timer timer = new Timer();
	private GradeAnalyser gradeAnalyser = new GradeAnalyser();
	private final TimerTask timerTask = configureTimerTask();
	private static Boolean running = Boolean.FALSE;

	// versiones
	private final TimerTask timerGetCompatibleVersionTask = configureTimerGetCompatibleVersionTask();
	private static final long tiempoConsulta = 24*60*60*1000; //cada un dia
	private Timer timer2 = new Timer();
	private static Boolean versionRunning = Boolean.FALSE;

	//TODO etapa 3: uncomment
	// push
	private final TimerTask timerGetNotificacionesPushTask = configureTimerGetNotificacionesPushTask();
	private static final long tiempoPedido = 60*1000; //cada un minuto x ahora //PropertyLoader.PUSH_FREQUENCY;
	private Timer timer3 = new Timer();
	private static Boolean pushRunning = Boolean.FALSE;
	// end comment


	public class WebCheckerBinder extends Binder {
		public WebChecker getService() {
			return WebChecker.this;
		}
	}

	@Override
	public void onCreate() {
		super.onCreate();
		startService();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		return Service.START_STICKY;
	}


	private TimerTask configureTimerTask(){

		TimerTask timerTask = new TimerTask() {

			@Override
			public void run() {
				running = Boolean.TRUE;
				if (NetworkManager.isNetworkAvailable(getApplicationContext())){
					long begin = System.currentTimeMillis();
					if (Devel.serviceDevel || Devel.fullDevel){
						Log.w(this.getClass().getName(), "Service Started");
					}
					List<Instance> instances = null;

					try {
						instances = gradeAnalyser.doGetGrades();
						if (instances != null){

							List<TusNotasNotification> notifications = gradeAnalyser.doAnaliseGrades(instances, getApplicationContext());
							TusNotasModel.getTusNotasModel(getApplicationContext()).updateProperty(Properties.NUM_WRONG_PASS, "0");

							for (TusNotasNotification notification: notifications) {
								notification.configureNotificacion(WebChecker.this);
								doNotify(notification);
							}
						}
						else{
							//NO CHANGES IN HTML
							if (Devel.serviceDevel || Devel.fullDevel){
								System.err.println("Probably, there were no changes in the XML");
							}
						}

					} catch (RemoteReadingException rwce) {
						if (rwce.getErrorCode().equals(GradeAnalyserStatuses.NOT_POSSIBLE_TO_CONNECT)){
							if (Devel.serviceDevel || Devel.fullDevel){
								Log.w(this.getClass().getName(), "Not Possible to Connect");
							}
						}
						else{
//							Integer wrongAttempts = PropertyLoader.NUM_WRONG_PASS+1;
//							if (wrongAttempts >= 2){
//
//								TusNotasNotification notification = new WrongPassNotification(WebChecker.this);
//								doNotify(notification);
//								TusNotasModel.getTusNotasModel(getApplicationContext()).updateProperty(Properties.NUM_WRONG_PASS, "-1");
//								PropertyLoader.getInstance(getApplicationContext());
//								running = Boolean.FALSE;
//								stopSelf();
//								return;
//							}
//							TusNotasModel.getTusNotasModel(getApplicationContext()).updateProperty(Properties.NUM_WRONG_PASS, wrongAttempts.toString());
//							PropertyLoader.getInstance(getApplicationContext());
						}
					} catch (ProcessingInstancesException pie) {
						//TODO DISPLAY ERROR TO THE USER
						running = Boolean.FALSE;
						stopSelf();
					}
					if (Devel.serviceDevel || Devel.fullDevel){
						Log.w(this.getClass().getName(), "Service ran OK in: " + (System.currentTimeMillis() - begin));
					}

				}else if (Devel.serviceDevel || Devel.fullDevel){
					Log.w(this.getClass().getName(), "Cannot run service because connection is not available");
				}
				running = Boolean.FALSE;
			}
		};
		return timerTask;
	}

	public static Boolean isRunning(){
		return running;
	}

	public static Boolean isVersionRunning(){
		return versionRunning;
	}

	//TODO etapa 3: uncomment
	public static Boolean isPushRunning(){
		return pushRunning;
	}
// end comment
	public void startChecking(){

		//TODO etapa 3: uncomment
		 servicePushSubscribe();
		// end comment

		String[] freqArray = getResources().getStringArray(R.array.frequency_millis_array);
		Integer frequency = new Integer(freqArray[PropertyLoader.FREQUENCY]);

		//TODO etapa 3: uncomment
		PropertyLoader.getInstance();
		Integer pushFrequency = PropertyLoader.PUSH_FREQUENCY;
		// end comment


		timer.scheduleAtFixedRate(timerTask, 0, frequency);
		timer2.scheduleAtFixedRate(timerGetCompatibleVersionTask, 0, tiempoConsulta);
		//TODO etapa 3: uncomment
		 timer3.scheduleAtFixedRate(timerGetNotificacionesPushTask, 0, pushFrequency);
		// end comment

	}

	private TimerTask configureTimerGetCompatibleVersionTask(){

		TimerTask timerTask = new TimerTask() {

			@Override
			public void run() {
				if(existsANewVersion()){
					Intent intent = new Intent("version");
					getApplicationContext().sendBroadcast(intent);
					Log.i(getClass().getSimpleName(), "Version Tick!!!"); 
				}
			}
		};
		return timerTask;
	}
	/*Hay una version superior a la mia*/
	private boolean existsANewVersion(){

		VersionAnalyser va = new VersionAnalyser();
		String appId = getApplicationContext().getPackageName();
		String clientVersion = getActualVersion();
		AppVersion version;
		try {
			version = va.doGetVersion(appId, clientVersion);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return !version.getIsLatest();
	}

	private String getActualVersion(){
		String app_ver;
		try
		{
			app_ver = this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
		}
		catch (NameNotFoundException e)
		{
			app_ver = "not_found";
			Log.v(getClass().getSimpleName(), e.getMessage());
		}
		return app_ver;
	}

	private void startService() {
		startChecking();
	}

	private void doNotify(TusNotasNotification notification){
		String ns = Context.NOTIFICATION_SERVICE;
		NotificationManager nm = (NotificationManager) getSystemService(ns);
		nm.notify(notification.getId(), notification);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		stopTimer();
		NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		nm.cancelAll();
	}

	private void stopTimer() {
		if (timer != null){
			timer.cancel();
		}
		if (timer2 != null){
			timer.cancel();
		}
		//TODO etapa 3: uncomment
		if (timer3 != null){
			timer.cancel();
		}
		servicePushUnSubscribe();
		// end comment

	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	//TODO etapa 3: uncomment 
	private TimerTask configureTimerGetNotificacionesPushTask(){
		TimerTask timerTask = new TimerTask() {
			@Override
			public void run() {
				pushRunning = Boolean.TRUE;

				Log.w("", "CHECKING FOR PUSH NOTIFICATIONS");

				// update property values
				PropertyLoader.getInstance(getApplicationContext());
				String subscribed = PropertyLoader.PUSH_SUBSCRIBED;

				if (subscribed.equals("true")){

					PushAnalyser pa = new PushAnalyser();
					String appId = getApplicationContext().getPackageName();
					ListaNotificaciones notifications = null;
					try {
						notifications = pa.doGetPushNotifications(appId, new IdGenerator(getApplicationContext()).getId());
					} catch (Exception e) {
						e.printStackTrace();
					}
					if (notifications==null  || notifications.getNotifications().isEmpty()){
						Log.w("","No push notifications to show");
						// nothing to display
						
						//TODO remove this test
						// notification acknowledge
//						PushAckAnalyser paa = new PushAckAnalyser();
//						try {
//							paa.doGetPushAck(appId);
//						} catch (RemoteReadingException e) {
//							e.printStackTrace();
//						} catch (ProcessingInstancesException e) {
//							e.printStackTrace();
//						}
						// end test
					} else {
						List<TusNotasNotification> barNotifications = pa.getBarNotifications(notifications, getApplicationContext());
						for (TusNotasNotification notification: barNotifications) {
							notification.configureNotificacion(WebChecker.this);
							doNotify(notification);
						}
						// notification acknowledge
						PushAckAnalyser paa = new PushAckAnalyser();
						try {
							paa.doGetPushAck(appId, new IdGenerator(getApplicationContext()).getId());
						} catch (RemoteReadingException e) {
							e.printStackTrace();
						} catch (ProcessingInstancesException e) {
							e.printStackTrace();
						}
					}
					// UPDATE TIMER IF NECESSARY
					PropertyLoader.getInstance();

					if (notifications!=null){
						//TODO remove or comment after testing
						notifications.setNextRequest(PropertyLoader.PUSH_FREQUENCY+1);
						// end 
						if (PropertyLoader.PUSH_FREQUENCY!=notifications.getNextRequest()){
							// update property value
							TusNotasModel tnm = TusNotasModel.getTusNotasModel(getApplicationContext());
							tnm.updateProperty(Properties.PUSH_FREQUENCY, Integer.toString((int) notifications.getNextRequest()));
						}
					}
				} else {
					Log.w("", "Not subscribed");
					// nothing to do: unsubscribed
				}
				pushRunning = Boolean.FALSE;
			}
		};
		return timerTask;
	}

	private void servicePushSubscribe(){
		try {
			PushSubscriptionAnalyser psa = new PushSubscriptionAnalyser();
			String appId = getApplicationContext().getPackageName();
            PushStatus status = psa.doSubscription(appId, new IdGenerator(getApplicationContext()).getId());
            TusNotasModel tnm = TusNotasModel.getTusNotasModel(getApplicationContext());
			// guardar como property si la suscripcion se realizo correctamente o no
			if( status.getEstado()==0){
				tnm.updateProperty(Properties.PUSH_SUBSCRIBED,"true");
			} else {
				tnm.updateProperty(Properties.PUSH_SUBSCRIBED,"false");
			}
		} catch (RemoteReadingException e) {
			e.printStackTrace();
		} catch (ProcessingInstancesException e) {
			e.printStackTrace();
		}
	}

	private void servicePushUnSubscribe(){
		try {
			PushUnsubscriptionAnalyser pua = new PushUnsubscriptionAnalyser();
			String appId = getApplicationContext().getPackageName();
			PushStatus status = pua.doUnSubscription(appId, new IdGenerator(getApplicationContext()).getId());
			TusNotasModel tnm = TusNotasModel.getTusNotasModel(getApplicationContext());
			// guardar como property si la suscripcion se realizo correctamente o no
			if( status.getEstado()==0){
				tnm.updateProperty(Properties.PUSH_SUBSCRIBED,"false");
			} else {
				tnm.updateProperty(Properties.PUSH_SUBSCRIBED,"true");
			}
		} catch (RemoteReadingException e) {
			e.printStackTrace();
		} catch (ProcessingInstancesException e) {
			e.printStackTrace();
		}
	}
	// end comment


}
